package com.evaluation.kexingcp.psycho.evaluation.sys.evaluation

import arrow.core.Either
import arrow.core.raise.catch
import arrow.core.raise.either
import arrow.core.raise.recover
import arrow.core.raise.withError
import arrow.core.right
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper
import com.evaluation.kexingcp.admin.api.entity.SysDept
import com.evaluation.kexingcp.admin.api.entity.SysMessageEntity
import com.evaluation.kexingcp.admin.api.entity.SysUser
import com.evaluation.kexingcp.admin.api.vo.OrgTreeVO
import com.evaluation.kexingcp.admin.api.vo.SysMessageVO
import com.evaluation.kexingcp.admin.service.SysDeptService
import com.evaluation.kexingcp.admin.service.SysMessageService
import com.evaluation.kexingcp.admin.service.SysRoleService
import com.evaluation.kexingcp.admin.service.SysTenantService
import com.evaluation.kexingcp.admin.service.SysUserService
import com.evaluation.kexingcp.common.core.util.SpringContextHolder
import com.evaluation.kexingcp.common.data.tenant.TenantContextHolder
import com.evaluation.kexingcp.common.websocket.distribute.MessageDO
import com.evaluation.kexingcp.common.websocket.distribute.RedisMessageDistributor
import com.evaluation.kexingcp.psycho.evaluation.sys.controller.vo.EvaluationUserInfo
import com.evaluation.kexingcp.psycho.evaluation.sys.entity.EvaluationTaskEntity
import com.evaluation.kexingcp.psycho.evaluation.sys.entity.EvaluationTaskUserRelEntity
import com.evaluation.kexingcp.psycho.evaluation.sys.service.EvaluationTaskService
import com.evaluation.kexingcp.psycho.evaluation.sys.service.EvaluationTaskUserRelService
import com.evaluation.kexingcp.psycho.evaluation.sys.sms.SmsError
import com.evaluation.kexingcp.psycho.evaluation.sys.sms.SmsService
import com.evaluation.kexingcp.psycho.evaluation.sys.sms.WebSocketMsg
import com.evaluation.kexingcp.psycho.evaluation.sys.utils.getUserInfo
import com.evaluation.kexingcp.psycho.evaluation.sys.utils.runInTransaction
import org.slf4j.LoggerFactory
import org.springframework.beans.BeanUtils
import org.springframework.stereotype.Service
import org.springframework.transaction.support.TransactionTemplate


data class TaskData(val pendingNum: Int, val completedNum: Int)

interface EvaluationTaskScaleService {
    fun publishTask(taskPublishRequest: TaskPublishRequest) : Either<EvaluationError, String>
    fun queryTaskData() : Either<EvaluationError, TaskData>
    fun queryTaskNum() : Either<EvaluationError, TaskData>
}

@Service
open class EvaluationTaskScaleImpl(
    private val transactionTemplate: TransactionTemplate,
    private val evaluationTaskUserRelService: EvaluationTaskUserRelService,
    private val evaluationTaskService: EvaluationTaskService,
    private val sysUserService: SysUserService,
    private val sysDeptService: SysDeptService,
    private val sysMessageService: SysMessageService,
    private val smsService: SmsService,
    private val sysRoleService: SysRoleService,
    private val sysTenantService: SysTenantService
    ) : EvaluationTaskScaleService {


    private val log = LoggerFactory.getLogger(EvaluationTaskScaleImpl::class.java)


    override fun publishTask(taskPublishRequest: TaskPublishRequest)  : Either<EvaluationError, String>
    = runInTransaction(transactionTemplate){
        var user = getUserInfo()
        val sysTenant = sysTenantService.getById(TenantContextHolder.getTenantId())

        val level = taskPublishRequest.taskLevel
            ?: if (taskPublishRequest.users.isNotEmpty()) {
                2
            } else {
                val dept = sysDeptService.getById(taskPublishRequest.deptId)
                if (dept.parentId == null) {
                    0
                } else {
                    if (sysDeptService.listDescendant(dept.deptId).isEmpty()) {
                        2
                    } else {
                        1
                    }
                }
            }



        if (level == 3) {
            val sysUser = sysUserService.selectUserVoById(taskPublishRequest.users[0].toLong())
            user = EvaluationUserInfo()
            BeanUtils.copyProperties(sysUser, user)
            user.id = sysUser.userId
        }

        val task = EvaluationTaskEntity().also {
            it.taskName = taskPublishRequest.taskName?.ifEmpty { "访客测评" }
            it.taskDescribe = taskPublishRequest.taskDescribe
            it.taskTime = taskPublishRequest.taskTime
            it.taskImportant = taskPublishRequest.taskImportant
            it.deptId = user.deptId
            it.chartConfig = taskPublishRequest.chartConfig
            it.canViewPersonalReport = taskPublishRequest.canViewPersonalReport
            it.teamFeatureBg = taskPublishRequest.teamFeatureBg
            it.taskLevel = level
        }


        if (level == -1) {
            task.scaleId = taskPublishRequest.scaleIds[0].toLong()
            evaluationTaskService.save(task)
            return@runInTransaction task.id.toString().right()
        }

        evaluationTaskService.save(task)

        // 待通知用户
        val notifyUserIds = mutableSetOf<Long>()

        fun save(userIds: List<Long>) {
            for (userId in userIds) {
                if (!sysRoleService.findRolesByUserId(userId).map { it.roleCode }.contains("GENERAL_USER")) continue

                for (scaleId in taskPublishRequest.scaleIds) {
                    evaluationTaskUserRelService.save(
                        EvaluationTaskUserRelEntity().also {
                            it.taskId = task.id
                            it.userId = userId
                            it.scaleId = scaleId.toLong()
                            it.completed = false
                        }
                    )
                    notifyUserIds.add(userId)
                }
            }
        }


        if (taskPublishRequest.users.isNotEmpty()) {
            save(taskPublishRequest.users.map { it.toLong() })
        } else {
            // 通过部门id查询所有子部门
            val deptIdList: List<SysDept> = sysDeptService.listDescendant(taskPublishRequest.deptId)
            for (dept in deptIdList) {
                val users = sysUserService
                    .list(QueryWrapper<SysUser>().eq("dept_id", dept.deptId))
                save(users.map { it.userId })
            }
        }

        if (level != 3) { // 访客测评不发通知
            val title = "您收到了新的测评任务《${taskPublishRequest.taskName}》，请及时完成。"
            smsService.sendWebSocketMsg(notifyUserIds.toList(), WebSocketMsg("task", title))

            // 生成站内信
            val sysMessageVO = SysMessageVO()
            sysMessageVO.title = title
            sysMessageVO.content = title
            sysMessageVO.allFlag = "0"
            sysMessageVO.category = "1"
            sysMessageVO.sort = 0
            sysMessageVO.userList = notifyUserIds.map { id -> OrgTreeVO().also { it.id = id } }

            sysMessageService.saveOrUpdateMessage(sysMessageVO)
            val message = sysMessageService
                .getOne(QueryWrapper<SysMessageEntity>().eq("send_flag", "0").orderByDesc("create_time"), false)
            if (message != null) {
                sysMessageService.sendMessage(message.id)
            }

            // 发送短信
            if (taskPublishRequest.isSendSms == 1) {
                val waitSendNum = notifyUserIds.size
                val availableNum = sysTenant.smsNum
                val canSendNum = if (availableNum - waitSendNum >= 0) { waitSendNum } else { availableNum }
                sysTenant.smsNum -= canSendNum
                sysTenantService.updateById(sysTenant)

                for (i in 0..<canSendNum) {
                    val notifyUser = sysUserService.getById(notifyUserIds.elementAt(i))
                    if(!notifyUser.phone.isNullOrBlank()) {
                        // 发送失败的忽略
                        recover({
                            smsService.sendNoticeEvaluationSms( notifyUser.phone )
                        }) { e: SmsError ->
                            log.error("发送短信失败: ${e.message}")
                        }
                    }
                }
            }
        }

        task.id.toString().right()
    }

    override fun queryTaskData(): Either<EvaluationError, TaskData> = either {
        val user = getUserInfo()

        // 查询用户角色列表
        val roles = sysRoleService.findRolesByUserId(user.id).map { it.roleCode }

        when {
            roles.contains("ROLE_ADMIN") -> {
                // 管理员
                TaskData(
                    evaluationTaskUserRelService
                        .count(QueryWrapper<EvaluationTaskUserRelEntity>().eq("completed", false)).toInt(),
                    evaluationTaskUserRelService
                        .count(QueryWrapper<EvaluationTaskUserRelEntity>().eq("completed", true)).toInt())
            }
            roles.contains("TEACHER") -> {
                // 查询老师已发布任务
                val taskIds = evaluationTaskService
                    .list(QueryWrapper<EvaluationTaskEntity>().eq("create_by", user.deptId))
                    .map { it.id }
                if (taskIds.isEmpty()) return@either TaskData(0, 0)

                TaskData(
                    evaluationTaskUserRelService
                        .count(QueryWrapper<EvaluationTaskUserRelEntity>()
                            .`in`("task_id", taskIds)
                            .eq("completed", false)).toInt(),
                    evaluationTaskUserRelService
                        .count(QueryWrapper<EvaluationTaskUserRelEntity>()
                            .`in`("task_id", taskIds)
                            .eq("completed", true)).toInt())
            }
            else -> {
                // 部门测评
                TaskData(
                    evaluationTaskUserRelService
                        .count(QueryWrapper<EvaluationTaskUserRelEntity>()
                            .eq("user_id", user.id).eq("completed", false)).toInt(),
                    evaluationTaskUserRelService
                        .count(QueryWrapper<EvaluationTaskUserRelEntity>()
                            .eq("user_id", user.id).eq("completed", true)).toInt())
            }
        }
    }

    override fun queryTaskNum(): Either<EvaluationError, TaskData> = either {
        TaskData(
            evaluationTaskService
                .count(QueryWrapper<EvaluationTaskEntity>().eq("is_team_report_completed", 0).lt("task_level", 3)).toInt(),
            evaluationTaskService
                .count(QueryWrapper<EvaluationTaskEntity>().eq("is_team_report_completed", 1).lt("task_level", 3)).toInt())
    }
}